package com.fattyCorps.battle.service.battle.effect;

import cn.hutool.extra.spring.SpringUtil;
import com.fattyCorps.battle.service.battle.Battle;
import com.fattyCorps.battle.service.battle.behavior.Behavior;
import com.fattyCorps.battle.service.battle.behavior.BhvProcessor;
import com.fattyCorps.battle.service.battle.data.BattleHero;
import com.fattyCorps.battle.service.battle.record.BattleRecorder;
import com.fattyCorps.common.enums.battle.EBehaviorEffectType;
import com.fattyCorps.common.enums.battle.EBehaviorType;
import com.fattyCorps.common.enums.battle.prop.EDynamicProp;
import com.fattyCorps.common.enums.battle.prop.EStaticProp;
import com.fattyCorps.common.enums.battle.triggerCondition.EBehaviorCondition;
import com.fattyCorps.common.mgr.Cfg;
import com.fattyCorps.common.mgr.GlobalConfig;
import com.fattyCorps.common.obj.config.SkillBuffMould;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.*;

// 效果处理器，负责收集到所有需要执行的效果后，执行效果具体逻辑
@Slf4j
public class EffectProcessor {
    Battle battle;
    List<Effect> effects = new ArrayList<>();
    List<Buff> newDamageBuffs = new ArrayList<>();
    Cfg cfg;
    GlobalConfig globalConfig;

    public EffectProcessor(Battle battle) {
        cfg = SpringUtil.getBean(Cfg.class);
        globalConfig = SpringUtil.getBean(GlobalConfig.class);
        this.battle = battle;
    }

    public void add(Effect e) {
        this.effects.add(e);
    }

    public void addAll(List<Effect> effects) {
        this.effects.addAll(effects);
    }

    public void clear() {
        this.effects.clear();
        this.newDamageBuffs.clear();
    }

    public void run(BhvProcessor.Event e) {
        EBehaviorCondition cnd = e.getCnd();

        // 默认攻击如果没有配，自动增加一个默认效果
        addDefaultNorAtt(e);
        if (effects.size() == 0) {
            return;
        }

//        log.info("回合：" + battle.getCurRound() + " 【发生事件】:" + e.getCnd().toString() + " 触发人：" +
//                e.getTrigger().toString());

        effects.sort(new Comparator<Effect>() {
            @Override
            public int compare(Effect o1, Effect o2) {
                return o2.getMould().getSort() - o1.getMould().getSort();
            }
        });

        // 承受伤害目标->伤害效果列表
        HashMap<BattleHero, List<Effect>> heroDamageEffects = new HashMap<>();
        // 承受伤害目标->增伤效果
        HashMap<BattleHero, String> heroIncDamageEffects = new HashMap<>();
        List<Effect> otherEffects = new ArrayList<>();

        // 筛选出对同一个目标的伤害效果，合并伤害效果，记做一次伤害，同时筛选出对该目标的增伤效果
        for (Effect effect : effects) {
            if (effect.getMould().getType().equals(EBehaviorEffectType.DynamicProp)) {
                if (effect.getMould().getDynamicCalcTargetProp().equals(EDynamicProp.Hp)) {
                    List<Effect> effects = heroDamageEffects.get(effect.getTarget());
                    if (effects == null) {
                        effects = new ArrayList<>();
                    }

                    effects.add(effect);
                    heroDamageEffects.put(effect.getTarget(), effects);

//                    log.info("触发【伤害效果】：" + effect.getMould().getName() + " 拥有者：" + effect.getTrigger() +
//                            " 目标：" + effect.getTarget().toString());
                }
            } else if (effect.getMould().getType().equals(EBehaviorEffectType.IncDamage)) {
                String orgIncDamage = heroIncDamageEffects.get(effect.getTarget());
                if (orgIncDamage == null) {
                    orgIncDamage = "1";
                }

                orgIncDamage = new BigDecimal(orgIncDamage).add(new BigDecimal(effect.getMould().getIncDamageValue()).
                        divide(new BigDecimal(EStaticProp.AMPLIFY_CFG))).toString();

//                log.info("触发【增伤效果】：" + effect.getMould().getName() + " 拥有者：" + effect.getTrigger() +
//                        " 目标：" + effect.getTarget().toString());

                heroIncDamageEffects.put(effect.getTarget(), orgIncDamage);
            } else {
                otherEffects.add(effect);
            }
        }

        // 统一处理伤害效果
        procDamageEffects(e, heroDamageEffects, heroIncDamageEffects);
        // 处理特殊事件对能量的影响
        addEnergyEffect(e, heroDamageEffects, otherEffects);
        // 处理非伤害效果
        procOtherEffects(e, cnd, otherEffects);
        // 如果产生了新的伤害类型buff，立即触发一次伤害效果
        procNewDamageBuff(heroIncDamageEffects);
        this.clear();
    }

    private void addDefaultNorAtt(BhvProcessor.Event e) {
        if (e.getCnd().equals(EBehaviorCondition.SelfNorAtt)) {
            boolean add = true;
            for (Effect effect : effects) {
                // 查看是否有替代普通攻击的伤害效果
                if (effect.getMould().getType().equals(EBehaviorEffectType.StaticProp)) {
                    add = false;
                    break;
                }
            }

            if (add) {
                effects.add(Effect.makeNorAtt(battle, e.getTrigger()));
                // 设置默认表现
                battle.getRecorder().lastElem().setDisplayId(globalConfig.getIntValue(GlobalConfig.DEFAULT_NOR_ATT_DISPLAY_ID));
            }
        }
    }

    private void addEnergyEffect(BhvProcessor.Event e, HashMap<BattleHero, List<Effect>> heroDamageEffects, List<Effect> otherEffects) {
        if (e.getCnd().equals(EBehaviorCondition.SelfNorAtt)) {
            // 被普通攻击的英雄，生成一个加能量的效果
            Iterator<Map.Entry<BattleHero, List<Effect>>> iterator = heroDamageEffects.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<BattleHero, List<Effect>> next = iterator.next();
                BattleHero targetHero = next.getKey();
                Effect effect = Effect.makeAddEnergy(battle, e.getTrigger(), targetHero, globalConfig.getIntValue(GlobalConfig.ATTACKED_ADD_ENERGY));
                effect.setShow(false);
                otherEffects.add(effect);
            }

            // 普通攻击的英雄，生成一个加能量的效果
            Effect effect = Effect.makeAddEnergy(battle, e.getTrigger(), e.getTrigger(), globalConfig.getIntValue(GlobalConfig.ATTACK_ADD_ENERGY));
            effect.setShow(false);
            otherEffects.add(effect);
        } else if (e.getCnd().equals(EBehaviorCondition.SelfSkillAtt)) {
            // 施法者成功出手后，能量归零，并且优先触发，防止后触发覆盖，后面增加能量的行为
            Effect effect = Effect.makeAddEnergy(battle, e.getTrigger(), e.getTrigger(), -e.getTrigger().getEnergy(), true);
            effect.setShow(false);
            otherEffects.add(effect);
        }
    }

    private void procDamageEffects(BhvProcessor.Event e, HashMap<BattleHero, List<Effect>> heroDamageEffects, HashMap<BattleHero, String> heroIncDamageEffects) {
        // 能量增伤
        BigDecimal energyIncDamageB = BigDecimal.valueOf(1);

        if (e != null && e.getCnd().equals(EBehaviorCondition.SelfSkillAtt)) {
            int energyCalc = e.getTrigger().getEnergy();
            final int MAX_ENERGY = 300;
            if (energyCalc > MAX_ENERGY) {
                energyCalc = MAX_ENERGY;
            }

            energyIncDamageB = BigDecimal.valueOf(energyCalc).divide(BigDecimal.valueOf(100));
        }

        // 先计算伤害效果，再计算其它效果
        Iterator<Map.Entry<BattleHero, List<Effect>>> iterator = heroDamageEffects.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<BattleHero, List<Effect>> next = iterator.next();
            BattleHero targetHero = next.getKey();
            List<Effect> value = next.getValue();

            long damage = 0;
            boolean isCritical = false;
            boolean isDebuff = false;
            for (Effect effect : value) {
                // 不能循环触发的行为
                EBehaviorType bhvType = effect.getMould().getCounterBehaviorType();
                if (bhvType != null && !bhvType.equals(EBehaviorType.None)) {
                    battle.getBhvProcessor().addCounterBhvType(effect.getMould().getCounterBehaviorType());
                }

                Effect.DamageRet damageRet = effect.getDamage();
                damage += damageRet.damage;
                if (!isCritical) {
                    isCritical = damageRet.isCritical;
                }

                if (!isDebuff) {
                    isDebuff = effect.isBuff();
                }
            }

            String incDamage = heroIncDamageEffects.get(targetHero);
            if (incDamage == null) {
                incDamage = "1";
            }

            // 普通增伤
            damage = BigDecimal.valueOf(damage).multiply(new BigDecimal(incDamage)).longValue();
            // 能量增伤
            damage = BigDecimal.valueOf(damage).multiply(energyIncDamageB).longValue();

            targetHero.underAttack(damage);
            battle.getBhvProcessor().clearCounter();

            BattleRecorder.EDamageType type = BattleRecorder.EDamageType.NorDamage;
            if (isCritical) {
                type = BattleRecorder.EDamageType.Critical;
            }

            if (isDebuff && damage > 0) {
                type = BattleRecorder.EDamageType.Dot;
            }

            // 记录
            battle.getRecorder().recordDamage(type, damage, targetHero);
        }
    }

    private void procOtherEffects(BhvProcessor.Event e, EBehaviorCondition cnd, List<Effect> otherEffects) {
        if (!battle.isOver()) {
            for (Effect effect : otherEffects) {
                EBehaviorEffectType type = effect.getMould().getType();
                if (effect.getTarget().isDead()) {
                    continue;
                }

//                log.info("触发【其它效果】" + effect.getMould().getName() + " 触发者：" + e.getTrigger().toString() + " 目标：" + effect.getTarget().toString());

                // 根据效果类型处理
                if (type.equals(EBehaviorEffectType.StaticProp)) {
                    // 静态属性应该是在计算伤害时，参与计算出属性结果时使用
                    continue;
                } else if (type.equals(EBehaviorEffectType.DynamicProp)) {
                    if (effect.getMould().getDynamicCalcTargetProp().equals(EDynamicProp.Energy)) {
                        int newEnergy = effect.getTarget().getEnergy() + Integer.valueOf(effect.getMould().getDynamicCalcValue());
                        // 修改能量的效果
                        effect.getTarget().setEnergy(newEnergy);

//                        log.info(effect.getTarget().toString() + " 能量变化为：" + effect.getTarget().getEnergy());
                    }
                } else if (type.equals(EBehaviorEffectType.AddBuff)) {
                    // 到这里buff的目标已经被计算过了
                    SkillBuffMould buffMould = cfg.getCfg(SkillBuffMould.class, effect.getMould().getBuffId());
                    Buff buff = new Buff(battle, buffMould, effect.getMould().getBuffDuration(), effect.getTarget(), effect.getTrigger(), cnd);
                    effect.getTarget().addBuff(buff);

                    if (buff.getBuffTypeMould().getDamage()) {
                        newDamageBuffs.add(buff);
                    }
                } else if (type.equals(EBehaviorEffectType.RemoveBuff)) {
                    // todo: 清理buff，没想好有哪些清理逻辑
                    continue;
                } else {
                    // todo: 待实现TriggerBehavior，目前无此类buff的需求
                    continue;
                }

                // 记录
                battle.getRecorder().recordEffect(effect);
            }
        }
    }

    private void procNewDamageBuff(HashMap<BattleHero, String> heroIncDamageEffects) {
        HashMap<BattleHero, List<Effect>> heroDamageEffects = new HashMap<>();
        for (Buff newBuff : newDamageBuffs) {
            List<Effect> effects = heroDamageEffects.get(newBuff.getOwner());
            if (effects == null) {
                effects = new ArrayList<>();
            }

            for (Behavior behavior : newBuff.getBehaviors()) {
                for (Effect effect : behavior.getEffects()) {
                    effect.setTarget(newBuff.getOwner());
                }

                effects.addAll(behavior.getEffects());
            }

            heroDamageEffects.put(newBuff.getOwner(), effects);
        }

        if (heroDamageEffects.size() > 0) {
            procDamageEffects(null, heroDamageEffects, heroIncDamageEffects);
        }
    }

}
